﻿/*
 * Copyright (c) <2012> <guangboo49@gmail.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this 
 * software and associated documentation files (the "Software"), to deal in the Software 
 * without restriction, including without limitation the rights to use, copy, modify, merge, 
 * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 
 * to whom the Software is furnished to do so, subject to the following conditions: 
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

using System;
using System.Text.RegularExpressions;

namespace Optparse {
    public abstract class ArgOptionBase<T> : IArgOption<T> {
        #region protected contructors

        protected ArgOptionBase(string alias, string name, string desc, string helptext) : this(alias, name, desc, helptext, true, default(T)) { }

        protected ArgOptionBase(string alias, string name, string desc, string helptext, T defaultValue) : this(alias, name, desc, helptext, false, defaultValue) { }

        private ArgOptionBase(string alias, string name, string desc, string helptext, bool valueRequired, T defaultValue) {
            if (string.IsNullOrEmpty(alias))
                throw new ArgumentNullException("alias", "The parameter alias must not be null or empty.");

            if (string.IsNullOrEmpty(name))
                throw new ArgumentNullException("name", "The parameter name must not be null or empty.");

            if (!FormatUtil.ValidateAlias(alias))
                throw new ArgumentOutOfRangeException("alias", "The parameter alias length must be less than 3 and greater than 2. You should type alias styles:-f, -fx.");

            if (!FormatUtil.ValidateName(name))
                throw new ArgumentOutOfRangeException("name", "The parameter name length must be less than 12 and greater than 3. You should type name styles:--file, --filename or --clslist.");

            if (!string.IsNullOrEmpty(desc) && desc.Length > 10)
                throw new ArgumentOutOfRangeException("desc", "The parameter desc length must be less than 10. You should type desc styles:FILENAME, FILELIST OR CLSLIST.");

            
            this.Alias = alias;
            this.Name = name;
            this.Description = desc;
            this.HelpText = helptext;
            this.ValueRequired = valueRequired;
            this.Default = defaultValue;
            this.Value = defaultValue;
        }

        #endregion

        #region properties

        public T Value { get; protected internal set; }
        public Type ValueType { get { return typeof(T); } }
        public T Default { get; protected set; }

        internal bool Required { get; set; }
        
        public bool ValueRequired { get; private set; }

        public string Name { get; private set; }

        public string Alias { get; private set; }
        public string HelpText { get; private set; }
        public string Description { get; private set; }

        public bool HasValue { get; internal set; }

        object IArgOption.Value { get { return this.Value; } }

        #endregion

        #region methods

        protected abstract bool Parse(string optValue, out T value);

        public virtual void Parse(string optValue) {
            T value;
            if (this.Parse(optValue, out value)) {
                this.Value = value;
            } else {
                throw new ArgValueParseException(this, optValue);
            }
        }

        #endregion
    }
}
